//the top-level GUI frame
package edu.olin.scheduler.gui;

import edu.olin.scheduler.common.*;
import edu.olin.scheduler.gui.schedule.*;
import edu.olin.scheduler.loader.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.tree.*;

public class GUIMain extends JFrame implements GUIPrefs.Listener, ActionListener, ItemListener {
    
    public static final String EXPAND_MESSAGE = "You have added a course to your schedule that is outside the current display.\nWould you like to see more of the day to include your new course?";
    
    private MeetingDisplay[] md;
    private ScheduleDisplay sched;
    private JSplitPane split;
    private JMenuBar menuBar;
    private TimeLine timeline;
    private CourseCatalogTree courseTree;
    private GUIMain topFrame;
    
    public GUIMain(){
        //initialize the JFrame
        initialize();
        topFrame = this;
        //register to listen for GUI preference changes
        GUIPrefs.addListener(this);
        
        //form a schedule
        Schedule schedule = new Schedule();
        //Display the schedule on-screen
        sched = new ScheduleDisplay(schedule);
        
        //create the JSplitPane
        split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,true); //continuous layout; split line is vertical
        split.setResizeWeight(0.5); //share extra space between left & right components
        split.setBorder(null); //no border
        sched.setPreferredSize(new Dimension(600,450));
        sched.setMinimumSize(new Dimension(300,200));

        //load the courses into the JTree
        Category root = null;
        try{
            //root = CourseLoader.loadCoursesFromFile("olin2007fall.txt");
            root = CourseLoader.loadCoursesFromResource("/edu/olin/scheduler/resources/catalogs/olin2007fall.txt");
            }catch(ParseException pe){ pe.printStackTrace();
            }
        if(root==null){ root = new Category("no courses loaded"); }
        courseTree = new CourseCatalogTree(root);
        courseTree.setRootExpanded(true);
        courseTree.setCheckListener(new TreeCheckListener(schedule));
        
        //Add stuff to the splitPane
        split.setLeftComponent(sched); //schedule display
        split.setRightComponent(courseTree); //future: stats/course selector panel
        
        //create a TimeLine and add it to the main GUI
        timeline = new TimeLine();
        Dimension d = new Dimension(50,5);
        timeline.setMinimumSize(d);
        timeline.setPreferredSize(d);
        timeline.setMaximumSize(d);
        getContentPane().add(timeline,BorderLayout.WEST);
        
        //add the splitPane to the main GUI
        getContentPane().add(split,BorderLayout.CENTER);
        
        //build the MenuBar and add it to the GUI
        menuBar = buildMainMenuBar();
        getContentPane().add(menuBar,BorderLayout.NORTH);
        
        //Make the JFrame visible
        pack();
        setLocationRelativeTo(null);
        setVisible(true);
        setExtendedState(MAXIMIZED_BOTH); //maximize to fill screen
        }

    private class TreeCheckListener extends CourseCatalogTree.CheckListener {
        Schedule schedule;
        public TreeCheckListener(Schedule schedule) {
            this.schedule = schedule;
            }
        public void directChange(TreeNode node, Integer state){
            if(node==null || !(node instanceof Course)){ return; }
            Course c = (Course)node;
            if(state==CourseCatalogTree.STATE_SELECTED){
                schedule.addCourse(c);
                SimpleTime start = GUIPrefs.getStart();
                SimpleTime end = GUIPrefs.getEnd();
                SimpleTime earliest = c.getEarliestTime();
                SimpleTime latest = c.getLatestTime();
                boolean ask = earliest.isBefore(start) || latest.isAfter(end);
                if(ask && ConfirmDialog.confirm(topFrame,EXPAND_MESSAGE)){
                    if(earliest.isBefore(start)){
                        int h = earliest.hours();
                        GUIPrefs.setStart(new SimpleTime(h,00));
                        }
                    if(latest.isAfter(end)){
                        int h = latest.hours();
                        if(latest.minutes()!=0 && h!=23){ h++; }
                        GUIPrefs.setEnd(new SimpleTime(h,00));
                        }
                    }
                }else{ schedule.removeCourse(c);
                }
            }
        public void indirectChangeFromBelow(TreeNode cause, TreeNode node, Integer state){
            directChange(node,state);
            }
        public void indirectChangeFromAbove(TreeNode cause, TreeNode node, Integer state){
            directChange(node,state);
            }
        }
    
    public JMenuBar buildMainMenuBar(){
        //main menu bar
        JMenuBar menuBar = new JMenuBar();
        //File Menu
        JMenu mnuFile = new JMenu("File");
        mnuFile.setMnemonic(KeyEvent.VK_F);
        menuBar.add(mnuFile);
            //File > New Schedule
            JMenuItem mnuFileNew = buildMenuItem(mnuFile,"New Schedule",KeyEvent.VK_N,"file>new");
            mnuFileNew.setEnabled(false);
            //File > Load Courses
            JMenuItem mnuFileLoad = buildMenuItem(mnuFile,"Load Courses",KeyEvent.VK_L,"file>loadcrscat");
            mnuFileLoad.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_L,KeyEvent.CTRL_DOWN_MASK));
            mnuFileLoad.setEnabled(false);
            //separator
            mnuFile.addSeparator();
            //File > Load Schedule
            JMenuItem mnuFileOpen = buildMenuItem(mnuFile,"Open Schedule",KeyEvent.VK_O,"file>open");
            mnuFileOpen.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O,KeyEvent.CTRL_DOWN_MASK));
            mnuFileOpen.setEnabled(false);
            //File > Save Schedule
            JMenuItem mnuFileSave = buildMenuItem(mnuFile,"Save Schedule",KeyEvent.VK_S,"file>save");
            mnuFileSave.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S,KeyEvent.CTRL_DOWN_MASK));
            mnuFileSave.setEnabled(false);
            //File > Export (Submenu)
            JMenu mnuFileExport = new JMenu("Export Schedule");
            mnuFileExport.setMnemonic(KeyEvent.VK_E);
            mnuFile.add(mnuFileExport);
                //File > Export > iCal
                JMenuItem mnuFileExportICal = buildMenuItem(mnuFileExport,"iCal",KeyEvent.VK_C,"file>export>ical");
                mnuFileExportICal.setEnabled(false);
                //File > Export > HTML
                JMenuItem mnuFileExportHTML = buildMenuItem(mnuFileExport,"HTML",KeyEvent.VK_H,"file>export>html");
                mnuFileExportHTML.setEnabled(false);
                //File > Export > Image
                JMenuItem mnuFileExportImage = buildMenuItem(mnuFileExport,"Image",KeyEvent.VK_I,"file>export>image");
                mnuFileExportImage.setEnabled(false);
            //separator
            mnuFile.addSeparator();
            //File > Quit
            JMenuItem mnuFileQuit = buildMenuItem(mnuFile,"Quit",KeyEvent.VK_Q,"file>quit");
            mnuFileQuit.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q,KeyEvent.CTRL_DOWN_MASK));
        //View Menu
        JMenu mnuView = new JMenu("View");
        mnuView.setMnemonic(KeyEvent.VK_V);
        menuBar.add(mnuView);
            //View > Preferences
            JMenuItem mnuViewPrefs = buildMenuItem(mnuView,"Preferences",KeyEvent.VK_P,"view>preferences");
            mnuViewPrefs.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_P,KeyEvent.CTRL_DOWN_MASK));
            mnuViewPrefs.setEnabled(false);
            //View > Preferences
            JMenuItem mnuViewReset = buildMenuItem(mnuView,"Reset View",KeyEvent.VK_R,"view>reset");
            mnuViewReset.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_R,KeyEvent.CTRL_DOWN_MASK));
            //separator
            mnuView.addSeparator();
            //View > 24-Hour Time (a checkbox menu item)
            JCheckBoxMenuItem mnuView12Hour = buildCheckboxMenuItem(mnuView,"12-Hour Time",KeyEvent.VK_T,"view>12hour");
            mnuView12Hour.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_T,KeyEvent.CTRL_DOWN_MASK));
            mnuView12Hour.setState(true);
            //View > Hide Weekends (a checkbox menu item)
            JCheckBoxMenuItem mnuViewWeekend = buildCheckboxMenuItem(mnuView,"Hide Weekends",KeyEvent.VK_W,"view>hideweekends");
            mnuViewWeekend.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_W,KeyEvent.CTRL_DOWN_MASK));
            mnuViewWeekend.setState(true);
            //View > Show Meeting Times (a checkbox menu item)
            JCheckBoxMenuItem mnuViewMeetTimes = buildCheckboxMenuItem(mnuView,"Hide Meeting Times",KeyEvent.VK_M,"view>hidemeetingtimes");
            mnuViewMeetTimes.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_M,KeyEvent.CTRL_DOWN_MASK));
            mnuViewMeetTimes.setState(true);
        //Courses Menu
        JMenu mnuCourses = new JMenu("Courses");
        mnuCourses.setMnemonic(KeyEvent.VK_C);
        menuBar.add(mnuCourses);
            //Courses > Collapse All
            JMenuItem mnuCoursesCollapseAll = buildMenuItem(mnuCourses,"Collapse All",KeyEvent.VK_C,"courses>collapse");
            mnuCoursesCollapseAll.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_OPEN_BRACKET,KeyEvent.CTRL_DOWN_MASK));
            //Courses > Expand All
            JMenuItem mnuCoursesExpandAll = buildMenuItem(mnuCourses,"Expand All",KeyEvent.VK_E,"courses>expand");
            mnuCoursesExpandAll.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_CLOSE_BRACKET,KeyEvent.CTRL_DOWN_MASK));
        //Help Menu
        JMenu mnuHelp = new JMenu("Help");
        mnuHelp.setMnemonic(KeyEvent.VK_H);
        menuBar.add(mnuHelp);
            //Help > Help
            JMenuItem mnuHelpHelp = buildMenuItem(mnuHelp,"Scheduler Help",KeyEvent.VK_H,"help>help");
            mnuHelpHelp.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F1,0));
            mnuHelpHelp.setEnabled(false);
            //Help > About
            JMenuItem mnuHelpAbout = buildMenuItem(mnuHelp,"About Scheduler",KeyEvent.VK_A,"help>about");
        return menuBar;
        }
    private JMenuItem buildMenuItem(JMenu parent, String text, int mnemonic, String actionCommand){
        JMenuItem j = new JMenuItem(text,mnemonic);
        j.setActionCommand(actionCommand);
        j.addActionListener(this);
        parent.add(j);
        return j;
        }
    private JCheckBoxMenuItem buildCheckboxMenuItem(JMenu parent, String text, int mnemonic, String actionCommand){
        JCheckBoxMenuItem j = new JCheckBoxMenuItem(text);
        j.setMnemonic(mnemonic);
        j.setActionCommand(actionCommand);
        j.addItemListener(this);
        parent.add(j);
        return j;
        }
    
    public void itemStateChanged(ItemEvent ie){
        Object item = ie.getItem();
        if(item==null){ return; }
        if(item instanceof JCheckBoxMenuItem){ //we're dealing with a JCheckBoxItem
            JCheckBoxMenuItem j = (JCheckBoxMenuItem) item;
            if(j.getActionCommand()==null){ return; } //not interested
            if(j.getActionCommand().equals("view>12hour")){ GUIPrefs.set24hour(!j.getState()); }
            if(j.getActionCommand().equals("view>hideweekends")){ GUIPrefs.setWeekendVisible(!j.getState()); }
            if(j.getActionCommand().equals("view>hidemeetingtimes")){ GUIPrefs.setShowMeetingTimes(!j.getState()); }
            }
        }
    
    public void actionPerformed(ActionEvent ae){
        String command = ae.getActionCommand();
        if(command==null||command.length()==0){ return; }
        if(command.equals("file>new")){
            sched.getSchedule().clear();
            return;
            }
        if(command.equals("file>quit")){
            System.exit(0);
            return;
            }
        if(command.equals("view>reset")){
            GUIPrefs.setStart(new SimpleTime(8,00));
            GUIPrefs.setEnd(new SimpleTime(12+6,00));
            }
        if(command.equals("help>about")){
            showAboutDialog();
            return;
            }
        if(command.equals("courses>expand")){
            courseTree.setAllExpanded(true);
            return;
            }
        if(command.equals("courses>collapse")){
            courseTree.setAllExpanded(false);
            courseTree.setRootExpanded(true);
            return;
            }
        }
    
    public void showAboutDialog(){
        JOptionPane.showMessageDialog(this,
            "Olin.Scheduler\n"+
            "-----\n"+
            "Coded in 2007 by:\n"+
            "  >  Jeffrey Stanton\n"+
            "  >  Annie Martin\n"+
            "-----\n"+
            "Olin.Scheduler is licensed\n"+
            "under the GPL license.  Visit \n"+
            "http://code.google.com/p/olin-scheduler/\n"+
            "for source code and more details."
            ,"About Olin.Scheduler",JOptionPane.INFORMATION_MESSAGE);
        }
    
    public void guiPrefsChanged(){
        repaint();
        if(timeline!=null){ timeline.repaint(); }
        }
    
    private void initialize(){
        //some vanilla initialization stuff
        //use the System look and feel; fails silently and reverts to the Metal PLAF
        try{ UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); }catch(Exception e){}
        getContentPane().setLayout(new BorderLayout());
        //We want the main program to end when the user closes the UI window
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setTitle("Olin.Scheduler");
        }

}
